import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/*
 * The Wrapper Facade class that is used for network communication.
 * This encapsulates the networking interface of the Socket class
 * and the input/output streams to write to it. This class, along with
 * the related IPv4Wrapper class  could be changed to support
 * Serial communication, modem communication, etc with out changing
 * any of the code in the other agents!
 */
public class NetCommunicationWrapper {
	static final int TCP_COMM_PORT = 1949;

	Socket sock = null;
	PrintWriter out = null;
	BufferedReader in = null;

	//Establish a connection to the given address.
	public boolean connect(String address) {
		try{
			sock = new Socket(address, TCP_COMM_PORT);
			out = new PrintWriter(sock.getOutputStream(), true);
			in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
			return true;
		}
		catch(UnknownHostException unknownHostEx){
			System.err.println("Cann't connect to host: " + address);
			return false;
		} catch (IOException iOEx) {
			System.err.println("Can't get the Input/Output from " + address);
			return false;
		}

	}

	// Check to see if there is someone listening on
	// the TCP_COMM_PORT at the given address.
	public static boolean checkConnectability(String address) {
		Socket tempSock = null;
		PrintWriter tempOut = null;
		BufferedReader tempIn = null;
		try{
			tempSock = new Socket(address, TCP_COMM_PORT);
			tempOut = new PrintWriter(tempSock.getOutputStream(), true);
			tempIn = new BufferedReader(new InputStreamReader(tempSock.getInputStream()));
			tempOut.println("#");
		}
		catch(Exception unknownHostEx){
			return false;
		}
		try {
			tempIn.readLine();
			tempOut.close();
			tempIn.close();
			tempSock.close();
			return true;
		} catch (Exception e) {
			return false;
		}

	}

	// Listen to the TCP_COMM_PORT. When a new connection is
	// requested, set the sock to the new connection and return true.
	public boolean listen(){
		ServerSocket servSock;
		int error = 0;
		try{
			servSock = new ServerSocket(TCP_COMM_PORT);
			error++;
			sock = servSock.accept();
			error++;
			out = new PrintWriter(sock.getOutputStream(), true);
			error++;
			in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
			servSock.close();
			return true;
		}
		catch(IOException e) {
			if(error == 0) {
				System.out.println("Failed to listen on " + TCP_COMM_PORT);
			}
			if(error == 1) {
				System.out.println("Failed to accept on " + TCP_COMM_PORT);
			}
			if(error == 2) {
				System.out.println("Failed to open PrintWriter on " + TCP_COMM_PORT);
			} else {
				System.out.println("Failed to open BufferedReader on " + TCP_COMM_PORT);
			}
			return false;
		}
	}

	//Send a data string.
	public void send(String dataString) {
		out.println(dataString);
	}


	// Close the connection.
	public void close() {
		try {
			sock.close();
			out.close();
			in.close();
		} catch (IOException e) {
			System.out.println("Failed to close properly");
		}


	}

	// Send the story server a request for the active story name.
	public String getStoryName()
	{
		receiveString();	//Send the Server a request for the active story name.
		send("#");
		return receiveString();
	}

	// Receive a string.
	public String receiveString() {
		int error = 0;
		try {
			String dataString = in.readLine();
			return dataString;
		} catch (Exception e) {
			System.err.println("Failed to readLine() ");
			return "#";
		}
	}
}
